home *** CD-ROM | disk | FTP | other *** search
- //──────────────────────────────────────────────────────────────────────────
- // Implementación del engine Phong/EnvMapping, Yann/Iguana
- //──────────────────────────────────────────────────────────────────────────
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sincos.h>
- #include <vga.h>
- #include "phong.h"
- #include "ph_fill.h"
-
- extern int tracing;
- #define TRACE(r,g,b) do { if (tracing) VGA_PutColor(0,r,g,b); } while(0)
-
- void *frame_buffer_adr = (void *)0xA0000;
-
- #define MAX_OBJECTS 5
- #define VERY_CLOSE 10
- #define BACKFACE_CULL
-
- struct O3DHeader {
- UWORD m_num_vertices;
- UWORD m_num_triangles;
- };
-
- static struct CGlobalTri {
- UWORD m_num_obj; // En qué objeto está el triangulo
- UWORD m_num_tri; // Qué triángulo dentro del objeto
- UWORD m_distance; // Distancia a la que está el tri.
- struct CGlobalTri *m_next; // Link
- };
-
- static struct CObject {
- struct CPoint *m_vertices;
- struct CNormal *m_normals;
- struct CTriangle *m_triangles;
- struct CPoint *m_xvertices;
- struct CPoint2D *m_proj_vertices;
- struct CNormal *m_xnormals;
- UWORD m_num_obj; // Identificador de objeto **//**
- UWORD m_num_vertices, m_num_triangles;
- BOOL m_all_ok;
- BOOL m_active;
- } s_objects[MAX_OBJECTS];
-
- static int s_num_objects = 0; // Cuántos son -^
-
- static struct CGlobalTri *s_list = 0; // Lista global de triángulos
- static struct CGlobalTri *s_pool = 0, *s_next = 0; // Pool para no hacer mallocs
-
-
- static struct CGlobalTri *GetTri(void) { // Acceso al pool
- return s_next++;
- }
-
- static void RestartPool(void) { // Inicializar la pool
- s_next = s_pool;
- }
-
- void PH_SetMode13BufferAdr(void *p) {
- frame_buffer_adr = p;
- }
-
- void *PH_GetMode13BufferAdr(void) {
- return frame_buffer_adr;
- }
-
- static struct CObject *NewObject(void) {
- struct CObject *p = s_objects + s_num_objects;
- if (s_num_objects == MAX_OBJECTS) {
- puts("ORRRROOOOORRRRRRRRR!!!!!!!!!!!!!");
- exit(-1);
- }
- p->m_num_obj = s_num_objects++;
- return p;
- }
-
- static void ReserveMem(struct CObject *p) {
- p->m_all_ok = FALSE;
-
- p->m_xvertices = calloc(p->m_num_vertices, sizeof(struct CPoint));
- if (!p->m_xvertices)
- return;
- p->m_xnormals = calloc(p->m_num_vertices, sizeof(struct CNormal));
- if (!p->m_xnormals) {
- free(p->m_xvertices);
- return;
- }
- p->m_proj_vertices = calloc(p->m_num_vertices, sizeof(struct CPoint2D));
- if (!p->m_proj_vertices) {
- free(p->m_xvertices);
- free(p->m_xnormals);
- return;
- }
- p->m_vertices = calloc(p->m_num_vertices, sizeof(struct CPoint));
- if (!p->m_vertices) {
- free(p->m_xvertices);
- free(p->m_xnormals);
- free(p->m_proj_vertices);
- return;
- }
- p->m_normals = calloc(p->m_num_vertices, sizeof(struct CNormal));
- if (!p->m_normals) {
- free(p->m_xvertices);
- free(p->m_xnormals);
- free(p->m_proj_vertices);
- free(p->m_vertices);
- return;
- }
- p->m_triangles = calloc(p->m_num_triangles, sizeof(struct CTriangle));
- if (!p->m_triangles) {
- free(p->m_xvertices);
- free(p->m_xnormals);
- free(p->m_proj_vertices);
- free(p->m_vertices);
- free(p->m_normals);
- return;
- }
- p->m_all_ok = TRUE;
- }
-
- HANDLE PH_BuildObj(BYTE *file_like_buffer) {
- struct O3DHeader hdr;
- struct CObject *p = NewObject();
- char *q = (char *)file_like_buffer;
- p->m_all_ok = FALSE;
-
- memcpy(&hdr, q, sizeof(struct O3DHeader));
- q += sizeof(struct O3DHeader);
-
- // Reservar memoria
- p->m_num_vertices = hdr.m_num_vertices;
- p->m_num_triangles = hdr.m_num_triangles;
- ReserveMem(p);
- if (!p->m_all_ok) {
- return 0;
- }
-
- // Leer los datos
- memcpy(p->m_vertices, q, p->m_num_vertices * sizeof(struct CPoint));
- q += p->m_num_vertices * sizeof(struct CPoint);
- memcpy(p->m_normals, q, p->m_num_vertices * sizeof(struct CNormal));
- q += p->m_num_vertices * sizeof(struct CNormal);
- memcpy(p->m_triangles, q, p->m_num_triangles * sizeof(struct CTriangle));
- q += p->m_num_triangles * sizeof(struct CTriangle);
- p->m_all_ok = TRUE;
- p->m_active = TRUE;
- return p - s_objects + 1;
- }
-
- void PH_DestroyObj(HANDLE h) {
- struct CObject *p = s_objects + h + 1;
-
- if (!p->m_all_ok)
- return;
-
- if (p->m_xvertices) free(p->m_xvertices);
- if (p->m_xnormals) free(p->m_xnormals);
- if (p->m_vertices) free(p->m_vertices);
- if (p->m_normals) free(p->m_normals);
- if (p->m_triangles) free(p->m_triangles);
- if (p->m_proj_vertices) free(p->m_proj_vertices);
-
- s_num_objects--; // Llevar la cuenta (para automatizar más
- // tarde algunas cosillas)
- }
-
- int PH_StartEngine(void) {
- // Se supone que ya se han construido todos los objetos.
- // Vamos a reservar la memoria que hace falta para todo el render
- int i;
- UWORD total_tris = 0;
-
- for (i = 0; i < s_num_objects; i++) {
- total_tris += s_objects[i].m_num_triangles;
- }
-
- if (!total_tris)
- return TRUE; // No hay objetos!
-
- s_pool = calloc(total_tris, sizeof(struct CGlobalTri));
- if (!s_pool)
- return 0; // No hay memoria
- RestartPool();
- return 1;
- }
-
- void PH_EndEngine(void) {
- free(s_pool);
- }
-
- static void ProjectVertices(struct CObject *pobj) {
- int i;
- struct CPoint *p = pobj->m_xvertices;
- struct CPoint2D *q = pobj->m_proj_vertices;
-
- for (i = 0; i < pobj->m_num_vertices; i++, p++, q++) {
- if (p->z < VERY_CLOSE) {
- q->x = 0;
- q->y = 0;
- continue;
- }
-
- q->x = (((DWORD)p->x << 8) / p->z) + 160;
- q->y = (((DWORD)p->y << 8) / p->z) + 100;
- }
- }
-
- static void DumpPolygons(struct CObject *p) {
- int i;
- struct CTriangle *pt = p->m_triangles;
- struct CPoint *pp1, *pp2, *pp3;
-
- // Añadir todos los triángulos del objeto actual a la lista global,
- // haciendo un sencillo clipping accept/reject
- for (i = 0; i < p->m_num_triangles; i++, pt++) {
- struct CGlobalTri *pgtri;
- pp1 = p->m_xvertices + pt->p1;
- pp2 = p->m_xvertices + pt->p2;
- pp3 = p->m_xvertices + pt->p3;
- if (pp1->z < VERY_CLOSE || pp2->z < VERY_CLOSE || pp3->z < VERY_CLOSE)
- continue;
-
- pgtri = GetTri();
-
- pgtri->m_num_obj = p->m_num_obj;
- pgtri->m_num_tri = i;
- pgtri->m_distance = pp1->z + pp2->z + pp3->z;
- pgtri->m_next = s_list;
- s_list = pgtri;
- }
- }
-
- void PH_DrawFrame(void) {
- int i;
- struct CGlobalTri *trav;
-
- // Comenzamos un render
- RestartPool();
- s_list = NULL;
-
- TRACE(32,32,0);
- // Llamar a ProjectVertices y DumpPolygons para todos los polígonos
- for (i = 0; i < s_num_objects; i++) {
- if (s_objects[i].m_active) {
- ProjectVertices(s_objects + i);
- DumpPolygons(s_objects + i);
- }
- }
-
- // Ordenar los triángulos de todos los objetos
- TRACE(16,16,16);
- SortTris();
-
- // Dibujarlos todos con ph_fill, haciendo backface-culling
- for (trav = s_list; trav; trav = trav->m_next) {
- BYTE z_val[3];
- struct CObject *pobj = s_objects + trav->m_num_obj;
- struct CTriangle *pt = pobj->m_triangles + trav->m_num_tri;
-
- TRACE(0,0,16);
-
- ex1 = pobj->m_proj_vertices[pt->p1].x;
- ey1 = pobj->m_proj_vertices[pt->p1].y;
- ex2 = pobj->m_proj_vertices[pt->p2].x;
- ey2 = pobj->m_proj_vertices[pt->p2].y;
- ex3 = pobj->m_proj_vertices[pt->p3].x;
- ey3 = pobj->m_proj_vertices[pt->p3].y;
-
- #ifdef BACKFACE_CULL
- if ((ex2-ex1)*(ey3-ey2)-(ey2-ey1)*(ex3-ex2) < 0) {
- continue;
- }
- #endif
-
- z_val[0] = pobj->m_xnormals[pt->p1].z;
- z_val[1] = pobj->m_xnormals[pt->p2].z;
- z_val[2] = pobj->m_xnormals[pt->p3].z;
- if (z_val[0] <= 0 && z_val[1] <= 0 && z_val[2] <= 0) {
- u1 = v1 = u2 = v2 = u3 = v3 = 0;
- } else {
- u1 = ((WORD)pobj->m_xnormals[pt->p1].x << 8) + 0x8000;
- v1 = ((WORD)pobj->m_xnormals[pt->p1].y << 8) + 0x8000;
- u2 = ((WORD)pobj->m_xnormals[pt->p2].x << 8) + 0x8000;
- v2 = ((WORD)pobj->m_xnormals[pt->p2].y << 8) + 0x8000;
- u3 = ((WORD)pobj->m_xnormals[pt->p3].x << 8) + 0x8000;
- v3 = ((WORD)pobj->m_xnormals[pt->p3].y << 8) + 0x8000;
- }
- TRACE(40,40,40);
- phong_fill();
- }
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // Ordena la lista s_list, utilizando el método RADIX-SORT con raíz 16,
- // por lo que hacen falta 4 pasadas
- /////////////////////////////////////////////////////////////////////////////
- #if 1
- #define RADIX 16
- #define PASSES 4
- #define EXTRACT(num, pass) \
- ((num >> (pass << 2)) & (RADIX-1))
- #else
- #define RADIX 256
- #define PASSES 2
- #define EXTRACT(num, pass) \
- ((num >> (pass << 3)) & (RADIX-1))
- #endif
- static void SortTris(void) {
- WORD i, j;
- struct CGlobalTri *heads[RADIX], *head, **tails[RADIX], **tail,
- *trav, *temp_next;
-
- // Ordenar la lista de triángulos global
- head = s_list;
- for (i = 0; i < PASSES; i++) {
- // Inicializar tails
- for (j = 0; j < RADIX; j++) {
- tails[j] = heads + j;
- }
-
- // Recorrer la lista principal y separar en RADIX listas
- for (trav = head; trav; trav = temp_next) {
- int k;
-
- temp_next = trav->m_next;
- k = EXTRACT(trav->m_distance, i);
- *tails[k] = trav;
- tails[k] = &trav->m_next;
- }
-
- // Terminar las listas
- for (j = 0; j < RADIX; j++) {
- *tails[j] = NULL;
- }
-
- // Añadir las listas a la lista principal
- head = NULL;
- tail = &head;
- //for (j = 0; j < RADIX; j++) { // Orden creciente
- for (j = RADIX - 1; j >= 0; j--) { // Orden decreciente
- if (heads[j]) {
- // Añadir la lista número 'j' al final
- *tail = heads[j];
- tail = tails[j];
- }
- }
- }
- s_list = head;
- }
-
- void PH_XFormVertices(HANDLE h, UWORD theta, UWORD phi, WORD x, WORD y, WORD z) {
- int i;
- DWORD cos_theta = Cos(theta);
- DWORD sin_theta = -Sin(theta);
- DWORD cos_phi = Cos(phi);
- DWORD sin_phi = Sin(phi);
- DWORD sinphi_sintheta = FPMult(sin_phi, sin_theta);
- DWORD sinphi_costheta = FPMult(sin_phi, cos_theta);
- DWORD cosphi_sintheta = FPMult(cos_phi, sin_theta);
- DWORD cosphi_costheta = FPMult(cos_phi, cos_theta);
- struct CPoint *p;
- struct CPoint *q;
- struct CObject *pobj = s_objects + h - 1;
-
- for (i = 0, p = pobj->m_vertices, q = pobj->m_xvertices ;
- i < pobj->m_num_vertices;
- i++, p++, q++) {
- /*
- q->x = x + FPMult(p->x, cos_theta) + FPMult(p->z, sin_theta);
- q->y = y + p->y;
- q->z = z + FPMult(p->z, cos_theta) - FPMult(p->x, sin_theta);
- */
- q->x = x + FPMult(p->x, cos_theta) + FPMult(p->z, sin_theta);
- q->y = y - FPMult(p->x, sinphi_sintheta)
- + FPMult(p->y, cos_phi)
- + FPMult(p->z, sinphi_costheta);
- q->z = z - FPMult(p->x, cosphi_sintheta)
- - FPMult(p->y, sin_phi)
- + FPMult(p->z, cosphi_costheta);
- }
- }
-
- #define NONE 8
- static int repr[] =
- { 2, 3, NONE, NONE, NONE, 4, NONE, 5, 1, NONE, 0, NONE, NONE, NONE, 7, 6 };
-
- static BYTE u_repr[] =
- { 127, 90, 0, -90, -127, -90, 0, 90, 0}; // Last is for NONE
-
- static BYTE v_repr[] =
- { 0, 90, 127, 90, 0, -90, -127, -90, 0};
-
- void PH_XFormNormals(HANDLE h, WORD theta, UWORD phi, WORD alpha) {
- int i;
- DWORD cos_theta, sin_theta, cos_phi, sin_phi;
- DWORD sinphi_sintheta;
- DWORD sinphi_costheta;
- DWORD cosphi_sintheta;
- DWORD cosphi_costheta;
- struct CObject *pobj = s_objects + h - 1;
- struct CNormal *r = pobj->m_normals;
- struct CNormal *s = pobj->m_xnormals;
-
- theta += alpha;
- cos_theta = Cos(theta);
- sin_theta = -Sin(theta);
- cos_phi = Cos(phi);
- sin_phi = Sin(phi);
- sinphi_sintheta = FPMult(sin_phi, sin_theta);
- sinphi_costheta = FPMult(sin_phi, cos_theta);
- cosphi_sintheta = FPMult(cos_phi, sin_theta);
- cosphi_costheta = FPMult(cos_phi, cos_theta);
-
- // Xform normals
- for (i = 0; i < pobj->m_num_vertices; i++) {
- /*
- s->x = FPMult(cos_sum, r->x) + FPMult(sin_sum, r->z);
- s->y = r->y;
- s->z = FPMult(cos_sum, r->z) - FPMult(sin_sum, r->x);
- */
- s->x = FPMult(r->x, cos_theta) + FPMult(r->z, sin_theta);
- s->y = - FPMult(r->x, sinphi_sintheta)
- + FPMult(r->y, cos_phi)
- + FPMult(r->z, sinphi_costheta);
- s->z = - FPMult(r->x, cosphi_sintheta)
- - FPMult(r->y, sin_phi)
- + FPMult(r->z, cosphi_costheta);
- if (s->z <= 0) {
- WORD u, v, code;
- u = s->x; v = s->y;
-
- code = (((UWORD)(v - (u<<1))) >> 15) << 3
- | (((UWORD)(u + (v<<1))) >> 15) << 2
- | (((UWORD)((v<<1) - u)) >> 15) << 1
- | (((UWORD)(v + (u<<1))) >> 15);
- s->x = u_repr[repr[code]];
- s->y = v_repr[repr[code]];
- }
-
- s++, r++;
- }
- }
-
- void PH_ActivateObj(HANDLE h, int active) {
- struct CObject *pobj = s_objects + h - 1;
- pobj->m_active = active;
- }
-
-